/**
	License:		Artistic license 2.0 (see license.txt, also available online at http://www.perlfoundation.org/artistic_license_2_0)
	Authors:		OrbitalLab (http://www.orbitallab.ru/moonglide/), 2007-2009

	File:			OpenGLHDR_hack.d
	Description:	hard code realisation of HDR
	Date:			04.11.2008 by Jurec
*/
module moonglide.renderer.opengl.OpenGLHDR_hack;

import
    moonglide.renderer.opengl.OpenGLRenderer,
    moonglide.renderer.IRendererBind,
    moonglide.renderer.IRenderer,
	moonglide.renderer.IRendererOffscreen,

	moonglide.renderer.opengl.GL,
	moonglide.renderer.opengl.OpenGLRenderer,

	moonglide.util.MoonUtil,
	moonglide.io.LogSystem,
	moonglide.math.MoonMath,

	moonglide.resources.resproc.texture.ResPTex,

    moonglide.renderer.opengl.OpenGLOffscreen,
	moonglide.renderer.opengl.OpenGLFilter;






class COpenGL_HDR
{
    protected:
        IRendererBind _binder;
        IRenderer _render;

        CLinearFilter _brightFilter;
        CBlurFilter _blurFilter;
        CDistortFilter _distFilter;
        CLinearFilter _moveFilter;

        uint _scrWid = 512,
             _scrHei = 512;

        CResTexture[6] BLOOM_TEXs;
        CResTexture noise_tex;
        const uint BLOOM_TEX_SIZE         =   256;

        COpenGLFBO bufScreen,
                   bufScreenTemp;


        COpenGLFBO_depthRB mainDepth;

    public:
        bool useTempDistortion = false;

        void setScreenSize( uint wid, uint hei )
        {
            _scrWid = wid;
            _scrHei = hei;

            BLOOM_TEXs[3].data[0].Resize( _scrWid, _scrHei );
            BLOOM_TEXs[4].data[0].Resize( _scrWid, _scrHei );
            _render.resLoader.upLoadTexture( BLOOM_TEXs[3] );
            _render.resLoader.upLoadTexture( BLOOM_TEXs[4] );
            bufScreen.resize( _scrWid, _scrHei );
            mainDepth.resize(_scrWid, _scrHei);

            if( useTempDistortion )
            {
                BLOOM_TEXs[5].data[0].Resize( _scrWid, _scrHei );
                bufScreenTemp.resize( _scrWid, _scrHei );
                _render.resLoader.upLoadTexture( BLOOM_TEXs[5] );
            }
        }


        void init()
        {
            noise_tex = CResTexture("noise1");
            noise_tex.data ~= CResTextureData( "data/noise.jpg", true );

            BLOOM_TEXs[0] = CResTexture("bloom tex1");
            BLOOM_TEXs[1] = CResTexture("bloom tex2");
            BLOOM_TEXs[2] = CResTexture("bloom tex3");

             for( int i=0;i<3;++i)
             {
                BLOOM_TEXs[i].data~=CResTextureData(BLOOM_TEXs[i].id~"_data", false);
                BLOOM_TEXs[i].data[$-1].CreateTempTex(256, 256, IL_RGB, Tex_2d );
             }

            BLOOM_TEXs[3] = CResTexture("screen tex");
            BLOOM_TEXs[3].data~=CResTextureData("screen tex data", false);
            BLOOM_TEXs[3].data[$-1].CreateTempTex(_scrWid, _scrHei, IL_RGB, Tex_2d );

            BLOOM_TEXs[4] = CResTexture("screen tex depth");
            BLOOM_TEXs[4].data~=CResTextureData("screen tex depth data", false);
            BLOOM_TEXs[4].data[$-1].CreateTempTex(_scrWid, _scrHei, IL_MOON_DEPTH24, Tex_2d );


            BLOOM_TEXs[5] = CResTexture("screen tex temper");
            BLOOM_TEXs[5].data~=CResTextureData("screenTemp tex data", false);
            BLOOM_TEXs[5].data[$-1].CreateTempTex(_scrWid, _scrHei, IL_RGB, Tex_2d );

            for( int i = 0;i < 6; ++i )
            {
                BLOOM_TEXs[i].data[$-1].useMipMap = false;
                BLOOM_TEXs[i].data[$-1].clampToEdge = true;
                BLOOM_TEXs[i].data[$-1].filter = ETextureFilter.tfTrilinear;////(i == 4 || i == 5) ? ETextureFilter.tfBilinear : ETextureFilter.tfTrilinear;
               _render.resLoader.upLoadTexture(BLOOM_TEXs[i]);
            }

            mainDepth = new COpenGLFBO_depthRB();
            mainDepth.create(_scrWid,_scrHei);

            bufScreen = new COpenGLFBO(_scrWid,_scrHei,false);
            bufScreen.init;
            bufScreen.bindAndAttachTexture2d(BLOOM_TEXs[3]);
            bufScreen.bindAndAttachTexture2d(BLOOM_TEXs[4]);
            //bufScreen.attachDepth(mainDepth);
            bufScreen.unBind;

            bufScreenTemp = new COpenGLFBO(_scrWid,_scrHei,false);
            if( useTempDistortion )
            {
                bufScreenTemp.init;
                bufScreenTemp.bindAndAttachTexture2d(BLOOM_TEXs[5]);
                bufScreenTemp.bindAndAttachTexture2d(BLOOM_TEXs[4]);
                //bufScreenTemp.attachDepth(mainDepth);
                bufScreenTemp.unBind;
            }

            _brightFilter = new CBrightFilter("bright", _render);
            _blurFilter = new CBlurFilter("blur", _render);
            _distFilter = new CDistortFilter("distort", _render);
            _moveFilter = new CLinearFilter("move", _render);
        }


        void deInit()
        {
        	delete bufScreen;
        	delete bufScreenTemp;

        	delete mainDepth;

            delete _brightFilter;
            delete _blurFilter;
            delete _distFilter;
            delete _moveFilter;

			// they all are already destroyed by resmanager.clear_all_resources
            foreach( ref tex; BLOOM_TEXs )
            	tex = null;

            noise_tex = null;
        }


        void beginTempRender()
        {
            bufScreen.unBind;
            if( !useTempDistortion )
                return;

            bufScreenTemp.bind();
            glClearColor(0.f,0.f,0.f,1.f);

            glDepthMask(GL_FALSE);
            glEnable(GL_DEPTH_TEST);

            glClear( GL_COLOR_BUFFER_BIT );
        }

        void endTempRender()
        {
            if( !useTempDistortion )
                return;
            bufScreenTemp.unBind();
            glClearColor(0.0,0.0,0.0,1.0);
            glDepthMask(GL_TRUE);
        }

        void beginRender()
        {
            GetGLError(__FILE__,__LINE__);

            bufScreen.bind;
            glClearColor(0.0,0.0,0.0,1.0);
            glClear( GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT );
        }


        void beginOnlyHdrRender()
        {
         //   bufBloom.bind;
         //   bufBloom.bindAndAttachTexture2d(BLOOM_TEXs[0]);
        }

        void endRender()
        {
           // bufScreen.unBind;

/// ///////////////////////////////////


    if( useTempDistortion )
    {
/// ///////////////////////////////////
/// gaussian blur
/*
            _moveFilter.setInput(_moveFilter.inTexName, BLOOM_TEXs[5]);
            _moveFilter.setOutput(BLOOM_TEXs[2]);
            _moveFilter.process;
*/
            _blurFilter.setInput(_blurFilter.inTexName, BLOOM_TEXs[5]);
            _blurFilter.setOutput(BLOOM_TEXs[1]);
            _blurFilter.setBlurOffset( Vector3f(0.005, 0, 0.05) );
            _blurFilter.process;

            _blurFilter.setInput(_blurFilter.inTexName, BLOOM_TEXs[1]);
            _blurFilter.setOutput(BLOOM_TEXs[2]);
            _blurFilter.setBlurOffset( Vector3f(0, 0.005, 0.05) );
            _blurFilter.process;

/// ///////////////////////////////////

            _distFilter.setInput(_distFilter.inTexName, BLOOM_TEXs[3]);
            _distFilter.setInput(_distFilter.inTexName1, BLOOM_TEXs[2]);
            _distFilter.setInput(_distFilter.inTexName2, noise_tex);
            _distFilter.setOutput(BLOOM_TEXs[5]);
            _distFilter.process;
    }


            _brightFilter.setInput( _brightFilter.inTexName, BLOOM_TEXs[3] );
            _brightFilter.setOutput( BLOOM_TEXs[2] );
            _brightFilter.process();

/// ///////////////////////////////////
/// gaussian blur
            _blurFilter.setInput(_blurFilter.inTexName, BLOOM_TEXs[2]);
            _blurFilter.setOutput(BLOOM_TEXs[1]);
            _blurFilter.setBlurOffset( Vector3f(0.005, 0, 0.4) );
            _blurFilter.process;

            _blurFilter.setInput(_blurFilter.inTexName, BLOOM_TEXs[1]);
            _blurFilter.setOutput(BLOOM_TEXs[2]);
            _blurFilter.setBlurOffset( Vector3f(0, 0.005, 0.4) );
            _blurFilter.process;

/*
            _dofFilter.setInput(CDOFFilter.inTexName, BLOOM_TEXs[3]);
            _dofFilter.setInput(CDOFFilter.inTexName1, BLOOM_TEXs[2]);
            _dofFilter.setInput("indepthtex2", BLOOM_TEXs[4]);
            _dofFilter.setOutput(BLOOM_TEXs[1]);
            _dofFilter.process;

/*
/// ///////////////////////////////////
/// ping-pong blur
            _resFilter128.setInput(_resFilter128.inTexName, BLOOM_TEXs[2]);
            _resFilter128.setOutput(BLOOM_TEXs[1]);
            _resFilter128.process;
            _resFilter128.setInput(_resFilter128.inTexName, BLOOM_TEXs[1]);
            _resFilter128.setOutput(BLOOM_TEXs[2]);
            _resFilter128.process;
/// ///////////////////////////////////
*/

/*
                _addFilter.setInput(_addFilter.inTexName1, BLOOM_TEXs[1]);
                _addFilter.setInput(_addFilter.inTexName2, BLOOM_TEXs[0]);
                _addFilter.setOutput(BLOOM_TEXs[1]);

                _addFilter.process;
*/


            GetGLError(__FILE__,__LINE__);


            glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);

            glViewport(0, 0, _scrWid, _scrHei);
            //  JLResize;
        }

        void renderBloom()
        {
            /// 2d render
            glEnable(GL_BLEND);
            glEnable(GL_TEXTURE_2D);
            glBlendFunc(GL_ONE,GL_ONE);
            glColor4f(1,1,1,1);

            if( useTempDistortion )
                _binder.bindTexture( BLOOM_TEXs[5] );
            else
                _binder.bindTexture( BLOOM_TEXs[3] );

            _render.fullScreenQuad;

            _binder.bindTexture( BLOOM_TEXs[2] );
            _render.fullScreenQuad;

            glDisable(GL_BLEND);

            glBindTexture(GL_TEXTURE_2D,0);
        }


        this (IRenderer bin)
        {
            _binder = bin.materialSys.resBinder;
            _render = bin;
        }

        ~this()
        {
            deInit;
        }

}
